fix(osv): resolve latest version before querying to eliminate false positives#20
Conversation
…ositives When a package is referenced without a version (e.g. `npx vite`, `npx playwright install chromium`), the OSV query was sent without a version field. OSV then returns vulnerabilities across ALL versions ever published, surfacing CVEs that have long since been patched. Real-world impact: `vite@latest` was reported with 5 HIGH vulnerabilities when the actual current release (`vite@8.0.8`) has zero. Same for `playwright@latest` (1 HIGH reported, 0 in current `1.59.1`). Fix: when no version is specified, resolve `latest` from the npm or PyPI registry first, then query OSV with that concrete version. On registry failure (404, timeout, network error), fall back to the previous unversioned query — keeps prior fail-closed behavior intact. The resolved version is also surfaced through `CheckResult.resolvedVersion` so the hook output shows `vite@8.0.8` instead of the misleading `vite@latest`. Closes #19 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughFehlt bei einer Paket-Anfrage die Version, wird jetzt zunächst die aktuelle Version aus npm- oder PyPI-Registry abgefragt und als Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Client as "index.ts\n(Patcher)"
participant OSVModule as "osv.ts\n(checkPackageVulnerabilities)"
participant Registry as "npm/PyPI\nRegistry"
participant OSV as "OSV API"
User->>Client: Anfrage (Paket, evtl. ohne Version)
Client->>OSVModule: checkPackageVulnerabilities(pkg)
OSVModule->>OSVModule: prüfe: version vorhanden?
alt version fehlt
OSVModule->>Registry: GET latest (registry.npmjs.org/... oder pypi.org/...)
Registry-->>OSVModule: resolvedVersion oder Fehler/404
end
alt resolvedVersion vorhanden
OSVModule->>OSV: POST /v1/query mit package + version = resolvedVersion
else keine resolvedVersion
OSVModule->>OSV: POST /v1/query mit package (kein version-Feld)
end
OSV-->>OSVModule: vulnerabilities[]
OSVModule-->>Client: { status: 'success', vulnerabilities, resolvedVersion? }
Client->>Client: displayVersion = pkg.version || resolvedVersion || "latest"
Client-->>User: Ergebnismeldung mit displayVersion und Vulnerabilities
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/osv.test.ts`:
- Around line 1-9: The global fetch stub created with vi.stubGlobal('fetch')
(and the mockFetch fn) must be torn down to avoid cross-test interference: add
an afterEach() that calls vi.unstubGlobal('fetch') (or vi.unstubAllGlobals())
and ensure mockFetch.mockReset() is still called in beforeEach/afterEach as
appropriate; update src/osv.test.ts to add afterEach(() => {
vi.unstubGlobal('fetch'); }) (reference vi.stubGlobal('fetch') and mockFetch) so
the global stub is removed between tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 34d6dc48-c72f-4b6a-aa45-814a67e95374
📒 Files selected for processing (3)
src/index.tssrc/osv.test.tssrc/osv.ts
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
CodeRabbit review on PR #20: the module-scoped vi.stubGlobal('fetch') persisted across the test file. Move stubbing into beforeEach and add afterEach with vi.unstubAllGlobals() so each test gets a fresh stub and the global is restored cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@coderabbitai resolve |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/osv.test.ts`:
- Around line 136-150: The test for network-error fallback needs an explicit
assertion that, despite the registry rejection, an unversioned OSV query was
still performed: after calling checkPackageVulnerabilities('vite', undefined,
'npm') assert that mockFetch was invoked for the OSV endpoint (e.g.,
'https://api.osv.dev/v1/query') and that the request payload corresponds to an
unversioned query (no resolved version sent), using the existing mockFetch and
osvResponse helpers to locate and inspect the call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 90f9fe8d-744c-4ea4-b139-1326b345c189
📒 Files selected for processing (1)
src/osv.test.ts
✅ Actions performedComments resolved and changes approved. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
latestfrom the npm/PyPI registry before querying OSV when no version is specifiedvite@8.0.8instead of misleadingvite@latest)Why
OSV returns vulnerabilities across all versions ever published when no version is given. PatchPilot was treating that result as if it applied to the version about to be installed, surfacing patched CVEs as active threats.
vitevite@8.0.8is patchedplaywrightplaywright@1.59.1is patchedCommon trigger:
npx <tool>for already-installed local binaries (vite, vitest, playwright, …). Hit by Vite itself, Playwright, and — meta-painfully — vitest while testing this very fix.Test plan
src/osv.test.tscovering: npm resolve, scoped npm encoding, PyPI resolve, skip when version provided, 404 fallback, network-error fallback, end-to-end vite reproductiontsc --noEmitcleannpx viteno longer fires the false positive after merge + npm publishnpm install lodash@4.17.20) still trips the hookCloses #19
🤖 Generated with Claude Code
Summary by CodeRabbit